<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模拟数据双向绑定原理</title></title>
</head>
<body>
    <div>
        Vue2响应式数据原理
    </div>
    <!-- 尚硅谷 响应式数据 -->
    <script>
        // let obj = {
        //     name:'张三',
        //     age:12,
        //     friend:{
        //         fname:'jake'
        //     }
        // }      
        // const abs = new Observer(obj)

        // function Observer(target){
        //     if(typeof target!=='object' || target === null){
        //         return target
        //     }
        //     const keys = Object.keys(obj)
        //     keys.forEach(key=>{
        //         Object.defineProperty(this,key,{
        //             get(){
        //                 return target[key]
        //             },
        //             set(newvalue){
        //                 if(newvalue!==target[key]){
        //                     console.log(key,'发生了改变',newvalue);
        //                     target[key] = newvalue
        //                 }
        //             }
        //         })
        //     })
        // }

        
    </script>

    <!-- 哈默 vue2 响应式数据 对象-->
    <script>
        var data = {
            name:'jake',
            age:20,
            friend:{
                name:'Amy',
                age:21,
                sex:'女'
            }
        }
        // 变成响应式数据
        Observer(data)

        function Observer(target){
            if(typeof target !== 'object' || target === null){
                return target
            }
            for(let key in target){
                Observer(target[key])  //如果对象中包含一个对象，那么也将其变成响应式数据 
                defineReactie(target,key,target[key])
            }
        }

        function defineReactie(target,key,value){
            Object.defineProperty(target,key,{
                get(){
                    return value
                },
                set(newvalue){
                    Observer(newvalue)
                    if(newvalue !== value){
                        value = newvalue
                        console.log('视图更新');
                    }
                }
            })
        }

        // Object.defineProperty() 监听不了数据的删除和新增
        // 为此 Vue2使用了特有的API  Vue.set()   Vue.delete()
    </script>

    <!-- 哈默 vue2 响应式数据 数组 -->
    <script>
        var data2 = {
            name:'jake',
            age:20,
            friend:{
                name:'Amy',
                age:21,
                sex:'女'
            },
            color:['blue','red','yellow'],
            objs:[
                {name:'001',age:12},
                {name:'002',age:14},
                {name:'003',age:16},
            ]
        }
        const oldArrayProto = Array.prototype
        const newArrayProto = Object.create(oldArrayProto);
        ['push','pop','shift','unshift','splice','slice'].forEach(methodName => {
            newArrayProto[methodName] = function(){
                console.log('更新视图');
                oldArrayProto[methodName].call(this, ...arguments)
            }
        });

        // 变成响应式数据
        Observer2(data2)

        function Observer2(target){
            if(typeof target !== 'object' || target === null){
                return target
            }
            // 如果是数组的活，就修改他的原型为自己重写好的
            if(Array.isArray(target)){
                target.__proto__ = newArrayProto
            }
            for(let key in target){
                Observer2(target[key])  //如果对象中包含一个对象，那么也将其变成响应式数据 
                defineReactie(target,key,target[key])
            }
        }

        function defineReactie(target,key,value){
            Object.defineProperty(target,key,{
                get(){
                    return value
                },
                set(newvalue){
                    Observer2(newvalue)
                    if(newvalue !== value){
                        value = newvalue
                        console.log('视图更新');
                    }
                }
            })
        }
        
    </script>
</body>
</html>